/**
 * 
 */
package cen5501c.server;

import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.Socket;
import java.util.Timer;
import java.util.TimerTask;

import cen5501c.common.*;

/**
 * @author Jiangyan Xu
 * 
 */
public class ServerWorker implements Runnable {

	public static final int LIFESPAN = 20 * 1000; // 20 seconds
	protected volatile boolean shouldStop;
	private Socket client;

	public ServerWorker(Socket client) {
		this.client = client;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see java.lang.Runnable#run()
	 */
	public void run() {
		Timer timer = new Timer();
		//Terminate the thread after the lifespan
		timer.schedule(new TimerTask() {
			@Override
			public void run() {
				shouldStop = true;
			}}, LIFESPAN);
		
		
		BufferedReader inFromClient = null;
		DataOutputStream outToClient = null;
		String cmd_string = null;
		try {
			inFromClient = new BufferedReader(new InputStreamReader(client
					.getInputStream()));
			outToClient = new DataOutputStream(client.getOutputStream());
			String welcome_msg = "+OK READY <LISTFILES> <GETFILE...> <GETDELAY...> <QUIT>\n";
			outToClient.writeBytes(welcome_msg);
			//All client->server commands have only one line
			while(!inFromClient.ready()) {
				if(shouldStop == true) {
					System.out.println("Timeout. Evicting the client");
				}
			}
			cmd_string = inFromClient.readLine();
			if(shouldStop) {
				System.out.println("Timeout. Evicting the client");
				return;
			}
			execCmd(outToClient, cmd_string);
		} catch (IOException e) {
			return;
		} finally {
			try {	
				client.close();
				System.out.println("Socket to " + client.getRemoteSocketAddress() + " closed");
				timer.cancel();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}

	/**
	 * @param outToClient
	 * @param cmd_string
	 */
	private void execCmd(DataOutputStream outToClient, String cmd_string) {
		CmdBase cmd = null;
		try {
			cmd = CmdParser.cmdFromString(cmd_string);
		} catch (Exception e) {
			//Illegal command
			ErrorCmd err = new ErrorCmd("Wrong arguments or Illegal syntax");
			try {
				outToClient.writeBytes(CmdParser.cmdToString(err));
				return;
			} catch (IOException e1) {
				e1.printStackTrace();
			}
		}
		
		//Command ready
		CmdBase cmdToReturn = null;
		if(cmd instanceof ListFilesCmd) {
			cmdToReturn = ServerFileManager.getList();
		} else if(cmd instanceof GetFileCmd) {
			try {
				cmdToReturn = ServerFileManager.getFile((GetFileCmd)cmd);
				if(cmdToReturn == null) {
					throw new Exception("Invalid GETFILE arguments");
				}
			} catch (Exception e) {
				ErrorCmd err = new ErrorCmd(e.getMessage());
				try {
					outToClient.writeBytes(CmdParser.cmdToString(err));
				} catch (IOException e1) {
					e1.printStackTrace();
				}
				return;
			}
		} else {
			ErrorCmd err = new ErrorCmd("No such command implemented on server");
			try {
				outToClient.writeBytes(CmdParser.cmdToString(err));
			} catch (IOException e1) {
				System.err.println("Transfer not successful");
			}
			return;
		}
		
		int i = 0;
		byte[] content = null;
		try {
			String stringToReturn = CmdParser.cmdToString(cmdToReturn);
			content = stringToReturn.getBytes();
			for(; i < content.length; i++) {
				if(!this.shouldStop) {
					outToClient.writeByte(content[i]);
				} else {
					System.out.println("Timeout. Evicting the client");
					return;
				}
			}
			System.out.println("Transfer succeeded");
		} catch (IOException e) {
			System.err.println("Transfer not successful");
		}
	}

}
